<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="utf-8">
  <title>Vue.js 组件 </title>
  <script src="https://unpkg.com/vue/dist/vue.js"></script>
</head>

<body>

  <!-- 
    组件（Component）是 Vue.js 最强大的功能之一。
    组件可以扩展 HTML 元素，封装可重用的代码。
    组件系统让我们可以用独立可复用的小组件来构建大型应用，几乎任意类型的应用的界面都可以抽象为一个组件树：
    注册一个全局组件语法格式如下：
      Vue.component(tagName, options)
    tagName 为组件名，options 为配置选项。注册后，我们可以使用以下方式来调用组件：
      <tagName></tagName>
   -->

  <!-- 全局组件
    所有实例都能用全局组件。 
  全局组件实例
    注册一个简单的全局组件 runoob，并使用它：
  -->


  <div id="app">
    <!-- 使用全局组件 -->
    <runoob></runoob>
    <!-- 使用局部组件 -->
    <child></child>

    <!-- 参数传递 -->
    <runoob2 message="hello!"></runoob2>
    <br>

    <!-- 动态传参 -->
    <div>
      <input v-model="parentMsg">
      <br>
      <child2 v-bind:message="parentMsg"></child2>
    </div>
    <br><br>

    <!-- 使用 v-bind 指令将 todo 传到每一个重复的组件中 -->
    <ol>
      <todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
    </ol>

  </div>

  <script>
    /* 注册全局组件 */
    Vue.component('runoob', {
      template: '<h1>自定义全局组件</h1>'
    })

    /* 局部组件 */
    var Child = {
      template: '<h1>自定义局部组件</h1>'
    }

    /* 
     Prop
      prop 是子组件用来接受父组件传递过来的数据的一个自定义属性。
      父组件的数据需要通过 props 把数据传给子组件，子组件需要显式地用 props 选项声明 "prop"： 
      注意: prop 是单向绑定的：当父组件的属性变化时，将传导给子组件，但是不会反过来。
    */
    // 注册
    Vue.component('runoob2', {
      // 声明 props
      props: ['message2'],
      // 同样也可以在 vm 实例中像 "this.message" 这样使用
      template: '<span>{{message2}}</span>'
    })

    /*     
      动态 Prop
      类似于用 v-bind 绑定 HTML 特性到一个表达式，也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时，该变化也会传导给子组件： 
    */
    Vue.component('child2', {
      props: ['message'],
      template: '<span>{{message}}</span>'
    })

    Vue.component('todo-item', {
      props: ['todo'],
      template: '<li>{{todo.text}}</li>'
    })

    /*    
    Prop 验证
      组件可以为 props 指定验证要求。
      为了定制 prop 的验证方式，你可以为 props 中的值提供一个带有验证需求的对象，而不是一个字符串数组。
      
      当 prop 验证失败的时候，(开发环境构建版本的) Vue 将会产生一个控制台的警告。

    type 可以是下面原生构造器：
      String
      Number
      Boolean
      Array
      Object
      Date
      Function
      Symbol
      type 也可以是一个自定义构造器，使用 instanceof 检测。
    */
    Vue.component("my-component", {
      props: {
        // 基础的类型检查 (`null` 和 `undefined` 会通过任何类型验证)
        propA: Number,
        // 多个可能的类型
        propB: [String, Number],
        // 必填的字符串
        propC: {
          type: String,
          required: true
        },
        // 带有默认值的数字
        propD: {
          type: Number,
          default: 100
        },
        // 带有默认值的对象
        propE: {
          type: Object,
          // 对象或数组默认值必须从一个工厂函数获取
          default: function () {
            return { message: "hello" }
          }
        },
        // 自定义验证函数
        propF: {
          validator: function (value) {
            // 这个值必须匹配下列字符串中的一个
            return ['sucess', 'warning', "danger"].indexOf(value) !== -1
          }
        }
      }
    })


    /* 创建组件根实例 */
    new Vue({
      el: '#app',
      components: {
        /* 只在父模板可用 */
        'child': Child
      },
      data: {
        parentMsg: "父控件内容",
        sites: [
          { text: "Runoob" },
          { text: "Google" },
          { text: "Taobao" },
          { text: "JinDong" }
        ]
      }
    })
  </script>


</body>

</html>